/*******************************************************************************

    
     Cloud Firewall - a browser extension/addon that allows users to block connections 
    to sites, pages and web resources (images, videos, etc) hosted in major cloud services
    if the user wishes to do so.
    Copyright (C) 2019 Niklas Poslovski
    Copyright (C) 2019 Gokulakrishna Sudharsan

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Home: https://notabug.org/nipos/cloud-firewall
*/
window.CSONStringify = module.exports;
var PopupApp = window.PopupApp || {};
PopupApp.storage = chrome.storage.local;
PopupApp.logging = false;
PopupApp.counts = {};
PopupApp.appVersion = "1.0.0";
PopupApp.settingsToggles = {};
PopupApp.settingsToggles.google = false;
PopupApp.settingsToggles.amazon = false;
PopupApp.settingsToggles.facebook = false;
PopupApp.settingsToggles.apple = false;
PopupApp.settingsToggles.microsoft = false;
PopupApp.settingsToggles.cloudflare = false;
PopupApp.settingsToggles.notInList = false; //always
PopupApp.hostname = "";
PopupApp.url = "";

async function getTabDetails() {
  try {
    let tabs = await browser.tabs.query({
      active: true,
      currentWindow: true
    });
    PopupApp.tabid = tabs[0].id;
    let url = tabs[0].url;
    PopupApp.urlFromQuery = url;
    try {
      if (!url.startsWith("moz-extension") || !url.startsWith("about:")) {
        let hostname = µBlock.URI.hostnameFromURI(url);
        PopupApp.url = hostname + µBlock.URI.pathFromURI(url);
        if (!PopupApp.url.endsWith("/")) {
          PopupApp.url = PopupApp.url + "/";
        }
        PopupApp.hostname = hostname;
        PopupApp.domainname = "";
        let a = hostname.split(".");
        if (a.length > 1) {
          let len = a.length;
          PopupApp.domainname = a[len - 2] + "." + a[len - 1];
        }
      } else {
        PopupApp.url = PopupApp.urlFromQuery;
        PopupApp.hostname = "";
      }
    } catch (e) {
      console.log("error in URL constructor");
    }
  } catch (e) {
    console.log("error in tabs.query");
  }
  PopupApp.getSettingStates();
}

getTabDetails();

PopupApp.log = function(msg) {
  if (PopupApp.logging) {
    console.log("Cloud Firewall: " + JSON.stringify(msg));
  }
};

PopupApp.openExcludePopup = () => {
  document.getElementById("excludePopup").classList.add("fade");
  document.getElementById("excludePopup").style.display = "block";
};

PopupApp.addToExcludes = (lifetime) => {
  document.getElementById("excludePopup").classList.remove("fade");
  document.getElementById("excludePopup").style.display = "none";
  chrome.runtime.sendMessage(
    {
      type: "addToExcludes",
      subtype: "fromPopup",
      tabid: PopupApp.tabid,
      url: PopupApp.url,
      domainname: PopupApp.domainname,
      lifetime: lifetime
    },
    resp => {
      if (resp === "Added to Excludes") {
        getTabDetails();
        // refresh the page.
      }
    }
  );
};

/*String.prototype.replaceAll = function(searchStr, replaceStr) {
  var str = this;
  //console.log("replaceAll called");
  // escape regexp special characters in search string
  searchStr = searchStr.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");

  return str.replace(new RegExp(searchStr, "gi"), replaceStr);
};*/

PopupApp.removeFromExcludes = () => {
  chrome.runtime.sendMessage(
    {
      type: "removeFromExcludes",
      subtype: "fromPopup",
      tabid: PopupApp.tabid,
      url: PopupApp.url,
      domainname: PopupApp.domainname
    },
    resp => {
      if (resp === "Removed from Excludes") {
        getTabDetails();
        // refresh the page.
      }
    }
  );
};

PopupApp.copyToClipboard = type => {
  let textElement = document.createElement("textarea");
  document.body.appendChild(textElement);
  let stats = JSON.parse(PopupApp.stringified_blockedUrls);
  stats.AddressBar_URL = PopupApp.urlFromQuery;
  let total = 0;
  if (!PopupApp.logging) {
    for (let i in stats.Counts) {
      total += stats.Counts[i];
      if (stats.Counts[i] === 0) {
        delete stats.Counts[i];
      }
    }
    stats.Counts.Total = total;

    for (let company in stats.Resources_Hosted_In_Cloud) {
      if (PopupApp.perPageStats[company] === 0) {
        delete stats.Resources_Hosted_In_Cloud[company];
      }
      if (stats.Resources_Hosted_In_Cloud.hasOwnProperty(company)) {
        for (let type in stats.Resources_Hosted_In_Cloud[company]) {
          if (stats.Resources_Hosted_In_Cloud[company][type].length < 1) {
            delete stats.Resources_Hosted_In_Cloud[company][type];
          }
        }
      }
    }
  } else {
    if (stats.Counts.hasOwnProperty("notInList")) {
      delete stats.Counts.notInList;
    }

    for (let i in stats.Counts) {
      total += stats.Counts[i];
    }
    stats.Counts.Total = total;
  }

  for (let i of Object.keys(stats.Resources_Hosted_In_Cloud)) {
    let k = i.charAt(0).toUpperCase() + i.slice(1);
    stats.Resources_Hosted_In_Cloud[k] = stats.Resources_Hosted_In_Cloud[i];
    delete stats.Resources_Hosted_In_Cloud[i];
  }

  for (let i of Object.keys(stats.Counts)) {
    if (i !== "Total") {
      let k = i.charAt(0).toUpperCase() + i.slice(1);
      stats.Counts[k] = stats.Counts[i];
      delete stats.Counts[i];
    } else {
      let total = stats.Counts[i];
      delete stats.Counts[i];
      stats.Counts.Total = total;
    }
  }

if(type === "popup") {
PopupApp.openUrl(browser.extension.getURL("blocklist.html")+"#"+encodeURIComponent(JSON.stringify(stats)));
  } if (type === "json") {
    let str = JSON.stringify(stats, null, 4);
    let strArray = str.split("\n");
    strArray.splice(2, 0, " ");
    for (let i = 0; i < strArray.length; i++) {
      if (
        i + 1 !== strArray.length &&
        strArray[i + 1].includes("Resources_Hosted_In_Cloud")
      ) {
        strArray[i] += "\n";
      }
    }
    textElement.value = strArray.join("\n");
  } else if (type === "yaml") {
    let str = json2yaml(stats);
    let strArray = str.split("\n");
    strArray.splice(1, 0, " ");
    for (let i = 0; i < strArray.length; i++) {
      if (
        i + 1 !== strArray.length &&
        strArray[i + 1].includes("Resources_Hosted_In_Cloud")
      ) {
        strArray[i] += "\n";
      }
    }
    textElement.value = strArray.join("\n");
  } else if (type === "cson") {
    let str = CSONStringify(stats, null, 4);
    let strArray = str.split("\n");
    strArray.splice(1, 0, " ");
    for (let i = 0; i < strArray.length; i++) {
      if (
        i + 1 !== strArray.length &&
        strArray[i + 1].includes("Resources_Hosted_In_Cloud")
      ) {
        strArray[i] += "\n";
      }
    }
    textElement.value = strArray.join("\n");
  } else if ("toml" === type) {
    //TOML
    let options = {};
    options.space = 2;
    let val = tomlify.toToml(stats, options);
    let strArray = val.split("\n");
    let index = strArray.findIndex(el =>
      el.includes("[Resources_Hosted_In_Cloud]")
    );
    let cindex = strArray.findIndex(o => o.includes("[Counts]"));
    // I wish to add some indentation for the List. Library defaults to float.
    // toml.js is already edited slightly to match our usage. The below for loop can be moved inside that file later
    for (let i = 0; i < strArray.length; i++) {
      if (strArray[i].startsWith("AddressBar_URL")) {
        continue;
      }
      if (i < index && i > cindex) {
        strArray[i] = strArray[i].replace(".0", "");
        strArray[i] =
          strArray[i].charAt(0).toUpperCase() + strArray[i].slice(1);
        strArray[i] = "  " + strArray[i];
      }
      if (strArray[i].includes("= [")) {
        strArray[i] = "    " + strArray[i];
      }
      if (strArray[i].startsWith("  ]")) {
        strArray[i] = "     " + strArray[i];
      }
      if (strArray[i].startsWith('    "')) {
        strArray[i] = "     " + strArray[i];
      }
    }

    textElement.value = strArray.join("\n");
  } else {
    //Plain
    let str = new JSON2Plain(stats).output;
    let strArray = str.split("\n");
    const index = strArray.findIndex(el =>
      el.startsWith("  Resources_Hosted_In_Cloud:")
    );

    for (let i in strArray) {
      if (strArray[i].includes("AddressBar_URL:")) {
        continue;
      }
      if (
        strArray[i].startsWith("  Counts:") ||
        strArray[i].startsWith("  Resources_Hosted_In_Cloud:")
      ) {
        strArray[i] = "\n" + strArray[i];
      }
      if (
        i > index &&
        (strArray[i].startsWith("    Google:") ||
          strArray[i].startsWith("    Facebook:") ||
          strArray[i].startsWith("    Amazon:") ||
          strArray[i].startsWith("    Cloudflare:") ||
          strArray[i].startsWith("    Microsoft:") ||
          strArray[i].startsWith("    Apple:"))
      ) {
        strArray[i] = "\n" + strArray[i] + "\n";
      }
      if (strArray[i].startsWith("        ") && strArray[i].includes(": ")) {
        strArray[i] = "  " + strArray[i];
      }
    }
    textElement.value = strArray.join("\n");
  }
  textElement.select();
  document.execCommand("copy");
  document.body.removeChild(textElement);
  var msg = browser.i18n.getMessage('copiedresourcenotification');
  chrome.notifications.create({
    type: "basic",
    title: "Cloud Firewall",
    message:
      msg +
      type.toUpperCase(),
    iconUrl: "images/shield32.png"
  });
};

//console.log(resp.shouldPersistRules);
PopupApp.getSettingStates = () => {
browser.storage.local.get(["settingsToggles","siteExceptions"],function(obj) {
if(!obj.siteExceptions) obj.siteExceptions = {};
if(!obj.settingsToggles) obj.settingsToggles = {};
for(let company in PopupApp.settingsToggles) {
if(company === "notInList") continue;
if(obj.siteExceptions.hasOwnProperty(PopupApp.domainname)) PopupApp.settingsToggles[company] = obj.siteExceptions[PopupApp.domainname][company];
else if(obj.settingsToggles.hasOwnProperty(company) && typeof obj.settingsToggles[company] !== undefined) PopupApp.settingsToggles[company] = obj.settingsToggles[company];
}
if(obj.siteExceptions.hasOwnProperty(PopupApp.domainname)) document.getElementById("resetRule").style.display = "initial";
else document.getElementById("resetRule").style.display = "none";
PopupApp.updateDetails();
});
};

PopupApp.openUrl = url => {
  //switch to open one if we have it to minimize conflicts
  chrome.tabs.query(
    {
      currentWindow: true
    },
    function(tabs) {
      //FIREFOXBUG: Firefox chokes on url:url filter if the url is a moz-extension:// url
      //so we don't use that, doing it the more manual way instead.
      for (var i = 0; i < tabs.length; i++) {
        if (tabs[i].url == url) {
          chrome.tabs.update(
            tabs[i].id,
            {
              active: true,
              url: url // to refresh the settings page to pick if something's changed in excludes
              // url:url is not required for help.html but reload doesn't harm.. :)
            },
            function(tab) {
              close();
            }
          );
          return;
        }
      }

      chrome.tabs.create({
        url: url
      });
      window.close();
    }
  );
};
/*
PopupApp.toggleDisabled = () => {
  PopupApp.storage.set(
    {
      disabled: !PopupApp.disabled
    },
    resp => {
      PopupApp.disabled = !PopupApp.disabled;
      let data;
      if (PopupApp.disabled == true) {
        data = "Cloud Firewall is disabled";
        console.log(data);
      } else {
        data = "Cloud Firewall is enabled";
        console.log(data);
      }
      chrome.runtime.sendMessage({
        type: "notify",
        data: data
      });
      DOM.popupDOM.updateDOM();
    }
  );
};


function addSitetoExclude() {
  sendExcludeMessage("AddtoExcludesList");
  // AddtoExcludesList AddtoTempExcludesList
} */
PopupApp.tabid = -10;
PopupApp.url = "";

PopupApp.updateDetails = () => {
  chrome.runtime.sendMessage(
    {
      type: "appDetails",
      subtype: "fromPopup",
      tabid: PopupApp.tabid,
      url: PopupApp.url,
      domainname: PopupApp.domainname
    },
    function(response) {
      //console.log(response.perPageStats);
      PopupApp.log(JSON.stringify(response));
      // logging.enabled = response.logstatus;
      PopupApp.logging = response.logstatus;
      PopupApp.isCFEnabled = response.isCFEnabled;
      PopupApp.counts = JSON.parse(response.counts);
      PopupApp.perPageStats = response.perPageStats;
      PopupApp.domainname = response.lastMainframeDomainName;
      PopupApp.isDomainExcluded = response.isDomainExcluded;
      //  PopupApp.settingsToggles = JSON.parse(response.settingsToggles);
      PopupApp.appVersion = response.appVersion;
      PopupApp.stringified_blockedUrls = response.stringified_blockedUrls;
      DOM.popupDOM.updateDOM();
      PopupApp.log(PopupApp);
    }
  );
};

PopupApp.toggle = async company => {
  try {
    let resp = await browser.runtime.sendMessage({
      type: "toggleSetting",
      subtype: "fromPopup",
      domainname: PopupApp.domainname,
      company: company
    });
    PopupApp.log(resp);
  } catch (e) {
    PopupApp.log("Toggling rule for " + company + " failed");
  } finally {
    PopupApp.getSettingStates();
  }
};
PopupApp.resetToggles = async () => {
  try {
    let resp = await browser.runtime.sendMessage({
      type: "toggleSetting",
      subtype: "fromPopup",
      domainname: PopupApp.domainname,
      command: "resetDefault"
    });
    PopupApp.log(resp);
  } catch (e) {
    PopupApp.log("Resetting rules failed");
  } finally {
    PopupApp.getSettingStates();
  }
};

PopupApp.onError = error => {
  PopupApp.log(`Error in popupApp : ${error}`);
};

PopupApp.toggleAll = async shouldBlock => {
  try {
    for (let el in PopupApp.settingsToggles) {
      if (el.toLowerCase().includes("not")) {
        continue;
      }
      if (PopupApp.settingsToggles[el] !== shouldBlock) {
        // console.log("toggling " + el + " to " + !PopupApp.settingsToggles[el]);
        PopupApp.toggle(el);
      }
    }
  } catch (e) {
    PopupApp.log("ToggleAll failed");
  }
};
